package com.apes.scm.pur.priceChange;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.generator.service.SequenceService;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.outbox.OutboxSubscriberService;
import com.apes.framework.plugin.soe.store.database.repository.BusinessAttributeValueRepository;
import com.apes.framework.util.DateUtil;
import com.apes.framework.util.MapUtil;
import com.apes.scm.account.account.model.InventoryBatch;
import com.apes.scm.account.account.model.InventoryMode;
import com.apes.scm.account.account.model.InventoryVo;
import com.apes.scm.account.account.repository.CooperationRepository;
import com.apes.scm.account.account.repository.InventoryBatchRepository;
import com.apes.scm.account.account.service.InventoryService;
import com.apes.scm.account.account.service.ProductAccountService;
import com.apes.scm.account.ledger.service.LedgerService;
import com.apes.scm.invoice.model.Invoice;
import com.apes.scm.invoice.model.InvoiceItem;
import com.apes.scm.invoice.service.InvoiceService;
import com.apes.scm.masterdata.enumeration.repository.EnumerationRepository;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 功能：采购变价单服务
 *
 * @author HuJianlin
 * @create 2018-06-27 11:35
 */
@Service("priceChangePlatformService")
public class PriceChangePlatformService extends DomainService {

    @Autowired
    PriceChangePlatformRepository priceChangePlatformRepository;
    @Autowired
    PriceChangeItemPlatformRepository priceChangeItemPlatformRepository;
    @Autowired
    ProductAccountService productAccountService;
    @Autowired
    private OutboxSubscriberService outboxSubscriberService;
    @Autowired
    private PartyRoleRepository partyRoleRepository;

    public PriceChangePlatform create(SimpleRequest request) {
        PriceChangePlatform priceChangePlatform = request.getO(PriceChangePlatform.class);
        priceChangePlatform.setState("sent");
        priceChangePlatform.computeAmt();
    /*    priceChangePlatform.getPriceChangeItemPlatforms().forEach(pricePlatItem -> {
            if (pricePlatItem.getBalanceQty() < pricePlatItem.getProductUomQty()) {
                throw new RuntimeException("变价数量大于结存数量！！");
            }
        });*/
        return priceChangePlatformRepository.saveAndFlush(priceChangePlatform);
    }

    public PriceChangePlatform update(SimpleRequest request) {
        checkData(request);
        PriceChangePlatform priceChangePlatform = request.getO(PriceChangePlatform.class);
        priceChangePlatform.setUpdateDate(new Date());
        priceChangePlatform.computeAmt();

        /*priceChangePlatform.getPriceChangeItemPlatforms().forEach(pricePlatItem -> {
            if (pricePlatItem.getBalanceQty() < pricePlatItem.getProductUomQty()) {
                throw new RuntimeException("变价数量大于结存数量！！");
            }
        });*/
        return priceChangePlatformRepository.saveAndFlush(priceChangePlatform);
    }

    public String delete(SimpleRequest request) {
        PriceChangePlatform priceChangePlatform = checkData(request);
        priceChangePlatform.setState("delete");
        priceChangePlatform.setDeleteDate(new Date());
        priceChangePlatform.setDeleteUid(request.getPerson());
        priceChangePlatformRepository.saveAndFlush(priceChangePlatform);
        return "删除成功！";
    }


    // 平台审核生成 公司采购变价
    public PriceChangePlatform generateCompanyPriceChange(SimpleRequest request) {
        PriceChangePlatform priceChangePlatform = request.getO(PriceChangePlatform.class);
        priceChangePlatform.setState("done");
        priceChangePlatform.setApproveUid(request.getPerson());
        priceChangePlatform.setApproveDate(new Date());
        return priceChangePlatformRepository.saveAndFlush(priceChangePlatform);

    }


    // 生成公司变价单
    public void produceCompanyPriceChange(SimpleRequest request) {
        PriceChangePlatform priceChangePlatformGetO = request.getO(PriceChangePlatform.class);
        if (!"done".equals(priceChangePlatformGetO.getState())) return;
        if (SpringManager.getBean(PriceChangeRepository.class).findAll(JpaDsl.toCriteriaByEq("source", priceChangePlatformGetO.getId())).size() != 0) return;
        PriceChangePlatform priceChangePlatform = priceChangePlatformRepository.findOne(priceChangePlatformGetO.getId());

        Map<Object, List<Object>> groupPriceChangePlatformIs = priceChangePlatform.getPriceChangeItemPlatforms().stream().collect(Collectors.groupingBy(item -> {
            return ((PriceChangePlatformItem) item).getCompany();
        }));

        String approveUid = priceChangePlatform.getApproveUid().getId();
        PriceChange priceChange = this.appendPriceChange(priceChangePlatform);
        groupPriceChangePlatformIs.forEach((k, v) -> {
            PriceChange newPriceChange = (PriceChange) priceChange.clone();
            newPriceChange.setCreator(approveUid);
            newPriceChange.setCompany((PartyRole) k);
            newPriceChange.setPriceChangeItems(this.appendPriceChangeItem((List) v, newPriceChange));

            PriceChange pricheChange = invoke("purchase.priceChange.create", newPriceChange);

            pricheChange.setApproveUid(SpringManager.getBean(PartyRoleRepository.class).findOne(approveUid));
            PriceChange approveReturnPriceChange = invoke("purchase.priceChange.approve", pricheChange);

            // 回写所变数量
            this.writebackPriceChangePlatformItem(priceChangePlatform, approveReturnPriceChange);
        });

    }

    // 审核 - 回写所变数量
    private void writebackPriceChangePlatformItem(PriceChangePlatform priceChangePlatform, PriceChange priceChange) {
        priceChange.getPriceChangeItems().forEach(priceChangeItem -> {
            priceChangePlatform.getPriceChangeItemPlatforms().forEach(priceChangePlatformItem -> {
                if (priceChangeItem.getOriginLine().equals(priceChangePlatformItem.getId() + "")) {
                    priceChangePlatformItem.setChangeBalanceQty(priceChangeItem.getChangeBalanceQty());
                    priceChangePlatformItem.setChangeSalesQty(priceChangeItem.getChangeSalesQty());
                    priceChangePlatformItem.setChangeProfitLossQty(priceChangeItem.getChangeProfitLossQty());
                    priceChangePlatformItem.setNewBatch(priceChangeItem.getNewBatch());
                }
            });
        });
    }

    private List<PriceChangeItem> appendPriceChangeItem(List<PriceChangePlatformItem> priceChangePlatformItems, PriceChange priceChange) {
        List<PriceChangeItem> priceChangeItems = new ArrayList<PriceChangeItem>();
        priceChangePlatformItems.stream().forEach(priceChangePlatformItem -> {
            PriceChangeItem priceChangeItem = new PriceChangeItem();
            priceChangeItem.setPriceChange(priceChange);
//            priceChangeItem.setCompany(priceChangePlatformItem.getCompany());
            priceChangeItem.setProduct(priceChangePlatformItem.getProduct());
            priceChangeItem.setOldBatch(priceChangePlatformItem.getOldBatch());
            priceChangeItem.setNewBatch(priceChangePlatformItem.getNewBatch());
            priceChangeItem.setProductUomQty(priceChangePlatformItem.getProductUomQty());
            priceChangeItem.setUom(priceChangePlatformItem.getUom());
            priceChangeItem.setOldPrice(priceChangePlatformItem.getOldPrice());
            priceChangeItem.setNewPrice(priceChangePlatformItem.getNewPrice());
            priceChangeItem.setAmtWithoutTax(priceChangePlatformItem.getAmtWithoutTax());
            priceChangeItem.setTaxAmt(priceChangePlatformItem.getTaxAmt());
            priceChangeItem.setAmtWithTax(priceChangePlatformItem.getAmtWithTax());
            priceChangeItem.setTax(priceChangePlatformItem.getTax());
            priceChangeItem.setInvoicedQty(priceChangePlatformItem.getInvoicedQty());
            priceChangeItem.setOriginLine(priceChangePlatformItem.getId() + "");
            priceChangeItems.add(priceChangeItem);
        });
        return priceChangeItems;
    }
    private PriceChange appendPriceChange(PriceChangePlatform priceChangePlatform) {
        PriceChange priceChange = new PriceChange();
        priceChange.setSource(priceChangePlatform.getId());
        priceChange.setSourceBusinessType(priceChangePlatform.getSourceBusinessType());
//        priceChange.setCompany(null);
        priceChange.setCooperation(priceChangePlatform.getCooperation());
        priceChange.setSupplier(priceChangePlatform.getSupplier());
//        priceChange.setClerk(priceChangePlatform.setClerk());
        priceChange.setPriceChangeMode(priceChangePlatform.getPriceChangeMode());
        priceChange.setTaxAmt(priceChangePlatform.getTaxAmt());
        priceChange.setAmtWithoutTax(priceChangePlatform.getAmtWithoutTax());
        priceChange.setAmtWithTax(priceChangePlatform.getAmtWithTax());
        priceChange.setAmtChangeBalanceQty(priceChangePlatform.getAmtChangeBalanceQty());
        priceChange.setNote(priceChangePlatform.getNote());
        priceChange.setConfirmationImg(priceChangePlatform.getConfirmationImg());
        priceChange.setCreateUid(priceChangePlatform.getApproveUid());
        priceChange.setApproveUid(priceChangePlatform.getApproveUid());
//        priceChange.setApproveDate(new Date());
        return priceChange;
    }


    // 校验数据
    public PriceChangePlatform checkData(SimpleRequest request){
        String id = request.get("id");
        PriceChangePlatform priceChangePlatform = priceChangePlatformRepository.findOne(id);
        if (priceChangePlatform == null) throw new RuntimeException("采购变价单：" + request.get("id") + " 在系统中不存在。");
        if (priceChangePlatform.getApproveDate() != null) throw new RuntimeException("采购变价单：" + request.get("id") + " 在系统中已审批。");

        return priceChangePlatform;
    }


    /**
     * 查找无内部供应商的供应商
     * @param simpleRequest
     * @return
     */
    public Page<PartyRole> findSupplier_notInside(SimpleRequest simpleRequest) {
        JSONObject getJO = simpleRequest.getJO();

        String id = "";
        JSONArray filtersArray = new JSONArray();
        JSONObject groupObj = getJO.getJSONObject("group");
        JSONArray conditionArray = getJO.getJSONArray("condition");
        if (groupObj != null) filtersArray = ((JSONObject) getJO.getJSONObject("group").getJSONArray("groups").get(0)).getJSONArray("filters");
        if (conditionArray != null && conditionArray.size() != 0) id = ((JSONObject) conditionArray.get(0)).getString("value");
        for (int i = 0, iLen = filtersArray.size(); i < iLen; i++) {
            JSONObject filtersObj = filtersArray.getJSONObject(i);
            String field = filtersObj.getString("field");
            String value = filtersObj.getString("value");
            if ("id".equals(field)) {
                id = value;
            }
        }
        if (StringUtils.isEmpty(id))  return partyRoleRepository.findSupplierNoId_changePrice(PageRequest.of(simpleRequest.get("page"), simpleRequest.get("size")));
        return partyRoleRepository.findSupplierInId_changePrice(id, PageRequest.of(simpleRequest.get("page"), simpleRequest.get("size")));
    }


    public JSONObject importPriceData(SimpleRequest request) {
        JSONObject getJO = request.getJO();
        JSONArray data = getJO.getJSONArray("data");
        JSONObject model = getJO.getJSONObject("model");
        JSONObject importData = getJO.getJSONObject("importData");
        Field[] fields = InventoryBatch.class.getDeclaredFields();

        List<String> columnNames = data.stream().map(dataO -> {return ((JSONObject) dataO).getString("name");}).collect(Collectors.toList());

        // 字段对照，变价字段 -> 批次字段
        Map<String, Integer> fieldCompare = this.fieldCompare(data);

        // 拼接有效数据返回
        JSONObject returnData = new JSONObject();
        JSONArray returnItems = new JSONArray();
        returnItems.add(columnNames);
        importData.forEach((k, v) -> {
            JSONArray tabaleContents = (JSONArray) v;

            // 查询批次编码
            List<Long> inventoryIds = this.filterInventoryId(tabaleContents);
            List<InventoryBatch> inventoryBatches = this.queryInventory(inventoryIds, model);

            // 过滤批次
            this.judgeSuitInventryBatch(inventoryBatches, inventoryIds);

            // 表格所有行
            for (int i = 1; i < tabaleContents.size(); i++) {

                if (tabaleContents.size() == 0) continue; //跳过空白行

                // 初始化数组
                List init = Collections.nCopies(columnNames.size(), "");
                List returnItems2 = new ArrayList(columnNames.size());
                returnItems2.addAll(init);

                // 获取相同批次
                long inventoryId = Long.valueOf(tabaleContents.getJSONArray(i).get(0).toString());
                InventoryBatch inventoryB = inventoryBatches.stream().filter(inventoryBatch -> {return inventoryBatch.getId() == inventoryId;}).findFirst().orElse(null);

                returnItems2.set(columnNames.indexOf(tabaleContents.getJSONArray(0).get(0)), inventoryB);
                // 相同匹配其他数据返回
                for (Field field:fields) {
                    String fieldName = field.getName();
                    String getMehod = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1, fieldName.length());
                    if (fieldCompare.containsKey(field.getName())) {
                        int index = fieldCompare.get(field.getName());
                        try {
                            returnItems2.set(index, inventoryB.getClass().getMethod(getMehod).invoke(inventoryB));
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }

                // 每列
                for (int j = 1; j < tabaleContents.getJSONArray(i).size(); j++) {
                    returnItems2.set(columnNames.indexOf(tabaleContents.getJSONArray(0).get(j)), tabaleContents.getJSONArray(i).get(j));
                }

                // 金额计算
                double newPrice = Double.parseDouble(returnItems2.get(fieldCompare.get("newPrice")).toString());
                double productUomQty = Double.parseDouble(returnItems2.get(fieldCompare.get("productUomQty")).toString());
                Map taxResult = invoke("account.tax.computeTaxAmount",
                        MapUtil.mapper("companyId", inventoryB.getCompany().getId(), "taxId", inventoryB.getTax().getId(), "priceUnit", newPrice - inventoryB.getTaxCostPrice(), "qty", productUomQty));
                returnItems2.set(fieldCompare.get("amtWithTax"), taxResult.get("totalIncluded"));
                returnItems2.set(fieldCompare.get("amtWithoutTax"), taxResult.get("totalExcluded"));
                returnItems2.set(fieldCompare.get("taxAmt"), taxResult.get("taxAmt"));
                returnItems.add(returnItems2);

            }
            returnData.put(k, returnItems);
        });
        return returnData;
    }

    private void judgeSuitInventryBatch(List<InventoryBatch> inventoryBatches, List<Long> inventoryIds) {
        // 是否有批次
        String message = "未找到合适批次，①.请检查批次编码是否填写正确<br/> ②.批次供应商是否和界面输入供应商匹配<br/>③.批次合作方式是否和界面选择方式方式一致";
        if (inventoryBatches.isEmpty()) throw new RuntimeException(message);

        // 仓储角色不能变价
        List<Long> warehouseRoleInventorys = new ArrayList<>();

        // 无效批次
        List<Long> invalidInventorys = new ArrayList<>(inventoryIds);

        inventoryBatches.forEach(inventoryBatch -> {
            PartyRole role = inventoryBatch.getCompany().getParty().getPartyRoles().stream().filter(partyRole -> {return partyRole.getRole().equals("Warehousing");}).findFirst().orElse(null);
            if (role != null) warehouseRoleInventorys.add(inventoryBatch.getId());

            if (inventoryIds.contains(inventoryBatch.getId())) invalidInventorys.remove(inventoryBatch.getId());
        });

        if (!warehouseRoleInventorys.isEmpty()) throw new RuntimeException("仓储公司角色不能变价，批次编码：" + warehouseRoleInventorys.toString());
        if (!invalidInventorys.isEmpty()) throw new RuntimeException(message + ", 批次编码：" +invalidInventorys.toString());
    }

    // 导入 - 提取表格批次
    private List<Long> filterInventoryId(JSONArray tabaleContents) {
        List<Long> inventoryIds = new ArrayList<>();
        for (int j = 1; j < tabaleContents.size(); j++) {
            inventoryIds.add(Long.valueOf(tabaleContents.getJSONArray(j).get(0).toString()));
        }
        return inventoryIds;
    }

    // 导入 - 查找批次
    public List<InventoryBatch> queryInventory(List<Long> inventoryIds, JSONObject model) {
        String supplierId = model.getJSONObject("supplier").getString("id");
        String cooperationId = model.getJSONObject("cooperation").getString("id");

        // 拼接条件 供应商 + 批次 + 合作方式 + 库存方式
        List<InventoryBatch> inventoryBatches = getBean(InventoryBatchRepository.class).findAll(
                JpaDsl.toCriteria("id", "in", inventoryIds, "supplier.id", "eq", supplierId, "cooperation.id", "eq", cooperationId)
        );

        return inventoryBatches;
    }

    // 导入 - 字段对照 [变价字段 -> 批次字段]
    private Map<String, Integer> fieldCompare(JSONArray data) {
        Map<String, Integer> fieldCompare = new HashMap<>();
        for (int i = 0, iLen = data.size(); i < iLen; i++) {
            JSONObject dataO = data.getJSONObject(i);
            String field = dataO.getString("field");
            switch (field) {
                case "maxQty":
                    fieldCompare.put("canPriceChangeQty", i);
                    break;
                case "oldPrice":
                    fieldCompare.put("taxCostPrice", i);
                    break;
                default:
                    fieldCompare.put(field, i);
            }
        }
        return fieldCompare;
    }

}
